package com.hzit.service.impl;

import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.hzit.common.entity.PageResult;
import com.hzit.entity.Classes;
import com.hzit.entity.Student;
import com.hzit.mapper.StudentMapper;
import com.hzit.service.IClassesService;
import com.hzit.service.IStudentService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.hzit.vo.StudentVo;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.CachePut;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.cache.annotation.Caching;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

/**
 * <p>
 *  服务实现类
 * </p>
 *
 * @author wf
 * @since 2023-08-16
 */
@Service
public class StudentServiceImpl extends ServiceImpl<StudentMapper, Student> implements IStudentService {
	@Autowired
	private IClassesService classesService;
	@Autowired
	// private RedisTemplate redisTemplate;
	private StringRedisTemplate redisTemplate;

	//1. 查询出所有的学生列表并处理每个学生关联的班级名称
	@Override
	public List<StudentVo> findAll() {
		// List<StudentVo> studentVos = new ArrayList<>();
		// for (Student student : this.list()) {
		// 	StudentVo vo = new StudentVo();
		// 	BeanUtils.copyProperties(student, vo);
		// 	Classes classes = classesService.getById(student.getCid());
		// 	vo.setCname(classes.getCname());
		// 	studentVos.add(vo);
		// }
		//或者
		List<StudentVo> collect = this.list().stream().map(m -> {
			StudentVo vo = new StudentVo();
			BeanUtils.copyProperties(m, vo);
			Classes classes = classesService.getById(m.getCid());
			vo.setCname(classes.getCname());
			return vo;
		}).collect(Collectors.toList());
		return collect;
	}

	//2. 分页查询
	@Override
	public PageResult<StudentVo> findByPage(Integer page, Integer pageSize) {
		//2.1 开始分页查询
		Page<Student> studentPage = this.page(new Page<>(page, pageSize));
		List<Student> records = studentPage.getRecords();
		//2.2 处理结果集数据
		List<StudentVo> collect = records.stream().map(m -> {
			StudentVo vo = new StudentVo();
			BeanUtils.copyProperties(m, vo);
			Classes classes = classesService.getById(m.getCid());
			vo.setCname(classes.getCname());
			return vo;
		}).collect(Collectors.toList());
		//2.3 返回
		return new PageResult<>(studentPage.getTotal(),collect,studentPage.getPages(),page);
	}

	//3. 分页带条件查询
	@Override
	public PageResult<StudentVo> search(Integer page, Integer pageSize, StudentVo vo) {
		//3.1 开始分页查询
		//3.1.1 拼凑查询条件
		QueryWrapper<Student> queryWrapper = new QueryWrapper<>();
		queryWrapper.like(StrUtil.isNotBlank(vo.getSname()), "sname", vo.getSname());
		queryWrapper.like(StrUtil.isNotBlank(vo.getAddr()), "addr", vo.getAddr());
		queryWrapper.eq(vo.getCid() != null && vo.getCid() != 0, "cid", vo.getCid());

		//3.1.2 开始分页查询
		Page<Student> studentPage = this.page(new Page<>(page, pageSize),queryWrapper);
		//3.2 处理结果集数据
		List<Student> records = studentPage.getRecords();
		List<StudentVo> collect = records.stream().map(m -> {
			StudentVo v = new StudentVo();
			BeanUtils.copyProperties(m, v);
			Classes classes = classesService.getById(m.getCid());
			v.setCname(classes.getCname());
			return v;
		}).collect(Collectors.toList());
		//3.3 返回
		return new PageResult<>(studentPage.getTotal(),collect,studentPage.getPages(),page);
	}

	//4. 查询所有的学生(缓存)
	@Override
	public List<StudentVo> findAll2() {
		//4.1 从redis中查询学生列表
		String studentListStr = redisTemplate.opsForValue().get("studentList");
		//4.2 将得到的字符串转换为学生集合
		List<StudentVo> students = JSON.parseArray(studentListStr, StudentVo.class);
		if(students != null && students.size() > 0){
			System.out.println("从缓存中取数据...");
			return students;
		}else{
			System.out.println("正在查询数据库...");
			//4.2 从数据库中查询学生列表
			students = this.findAll();
			//4.3 将查询出的学生列表放到redis中
			redisTemplate.opsForValue().set("studentList",JSON.toJSONString(students));
		}

		return students;
	}

	//5. 删除学生前，从redis中清空学生列表，下次再查询时就从数据库直接查询再放到redis中 (原生写法，没有使用springcache前)
	@Override
	public void deleteById(Integer id) {
		//5.1 从redis中删除学生列表
		redisTemplate.delete("studentList");
		//5.2 从数据库中删除学生
		this.removeById(id);
	}

	//6. 使用springcache缓存学生
	@Override
	// value: 名称空间的名字 key: 是放在名称空间后的名字 ,此时的redis的全名为： students::findAll3
	// @Cacheable: 代表每次检查缓存中是否有指定value::key为名字的缓存，如果有就直接返回不调用方法，否则，就调用方法并添加redis中
	@Cacheable(key = "#root.methodName",value = "students")
	public List<StudentVo> findAll3() {
		System.out.println("正在访问数据库。。。");
		return this.findAll();
	}

	//7. 修改学生
	@Override
	// @CachePut: 每次都调用方法，以指定value::key为redis中的缓存名字，以方法返回值为值放到redis中，用于同步缓存
	@CachePut(value = "student",key = "#result.sid")
	public Student update(Student student) {

		this.updateById(student);
		return student;
	}

	//8. 删除学生
	@Override
	//@Cacheict： 代表删除指定value::key的redis缓存数据
	// @CacheEvict(value="students",key="'findAll3'")
	// allEntries=true,代表删除指定名称空间students下的所有的key的缓存
	// @CacheEvict(value="students",allEntries = true)
	@Caching(
			// ① 在此处可以定义多个@CacheEvict注解
			evict = {
					@CacheEvict(value="students",key="'findAll3'")
			}
	)
	public void delete(Integer id) {
		this.removeById(id);
	}


}
